import Data.List (intersect)
import Utils (readInt, tok, at)

type Card  = ([Int], [Int])
type Stash = [(Int, Int)]

-- Card 1: 41 48 83 86 17 | 83 86  6 31 17  9 48 53
parseLine :: String -> Card
parseLine s = 
    (wins, numbers)
    where
        wins    = map readInt . tok " " $ left
        numbers = map readInt . tok " " $ right
        left    = tokens !! 1
        right   = tokens !! 2  
        tokens  = tok ":|" s   -- ["Card 1", " 41 48 83 86 17 ", " 83 86  6 31 17  9 48 53"]

nbMatches :: Card -> Int
nbMatches = length . uncurry intersect

------------
-- Part 1 --
------------

scoreCard :: Card -> Int
scoreCard card
    | m >= 1    = 2 ^ (m - 1)
    | otherwise = 0
    where
        m = nbMatches card

------------
-- Part 2 --
------------

step :: Stash -> Stash
step [] = []
step ((nbMatches, nbOwned):rest) = 
    changeds ++ unchangeds
    where
        changeds = map (\(m, o) -> (m, o + nbOwned)) (take nbMatches rest)
        unchangeds = drop nbMatches rest

main = do
    contents <- readFile "input.txt"
    let cards = map parseLine . lines $ contents

    print $ sum . map scoreCard $ cards

    let stash = zip (map nbMatches cards) (repeat 1)
    let steps = takeWhile (/=[]) $ iterate step stash

    print $ sum . map snd . map head $ steps

    